﻿namespace blackhouse.mojoPortalExtend {
	using log4net;
	using mojoPortal.Business;
	using mojoPortal.Business.WebHelpers;
	using mojoPortal.Web;
	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Collections.ObjectModel;
	using System.Collections.Specialized;
	using System.Configuration;
	using System.Text;
	using System.Web;
	using System.Web.Caching;

	public class ExpandedSiteMapProvider : StaticSiteMapProvider {
		private const string CacheDependencyName = "siteMapCacheDependency";
		private string iconBaseUrl = "~/Data/SiteImages/FeatureIcons/";
		private static readonly ILog log = LogManager.GetLogger(typeof(ExpandedSiteMapProvider));
		private Collection<PageSettings> menuPages;
		private Dictionary<int, SiteMapNode> nodes = new Dictionary<int, SiteMapNode>(0x10);
		private readonly object objLock = new object();
		private SiteMapNode rootNode;
		private bool sslIsAvailable = false;
		private bool useUrlRewriter = true;

		public override SiteMapNode BuildSiteMap() {
			lock (this) {
				if (this.rootNode != null) {
					return this.rootNode;
				}
				this.menuPages = CacheHelper.GetMenuPages();
				int depth = 0;
				if (this.menuPages != null) {
					this.rootNode = this.CreateRootNode();
					foreach (PageSettings page in this.menuPages) {
						if (page.ParentId <= -1) {
							SiteMapNode node = this.CreateSiteMapNode(page, depth);
							try {
								this.AddNode(node, this.GetParentNode(page));
							}
							catch (InvalidOperationException ex) {
								log.Error("failed to add node to sitemap", ex);
							}
							catch (HttpException ex) {
								log.Error("failed to add node to sitemap", ex);
							}
							if (page.UseUrl && page.Url.StartsWith("http")) {
								node.Url = page.Url;
							}
						}
					}
				}
			}
			CacheDependency cacheDependency = CacheHelper.GetSiteMapCacheDependency();
			HttpRuntime.Cache.Insert("siteMapCacheDependency", new object(), cacheDependency, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, new CacheItemRemovedCallback(this.OnSiteMapChanged));
			return this.rootNode;
		}

		protected override void Clear() {
			lock (this.objLock) {
				this.rootNode = null;
				this.nodes.Clear();
				base.Clear();
			}
		}

		private void CreateChildNodes(mojoSiteMapNode node, PageSettings page, int depth) {
			foreach (PageSettings p in this.menuPages) {
				if (p.ParentId == page.PageId) {
					SiteMapNode childNode = this.CreateSiteMapNode(p, depth);
					try {
						this.AddNode(childNode, node);
					}
					catch (InvalidOperationException ex) {
						log.Error("failed to add node to sitemap", ex);
					}
					catch (HttpException ex) {
						log.Error("failed to add node to sitemap", ex);
					}
					if (p.UseUrl && p.Url.StartsWith("http")) {
						childNode.Url = p.Url;
					}
				}
			}
		}

		protected virtual void CreateExpandedChildNodes(SiteMapNode parentNode) {
			string expandMenuAss = ConfigurationManager.AppSettings["expandMenu" + parentNode.Key];
			if (!string.IsNullOrEmpty(expandMenuAss)) {
				try {
					ExpandedSiteMap expandMenu = Activator.CreateInstance(Type.GetType(expandMenuAss, false, true), new object[] { this, parentNode }) as ExpandedSiteMap;
					if (expandMenu != null) {
						this.AddExpandedNodes(expandMenu.GetNodes());
					}
				}
				catch (Exception e) {
					log.Error("Błąd przy expanded menu", e);
				}
			}
		}

		protected void AddExpandedNodes(mojoSiteMapNode[] nodes) {
			foreach (mojoSiteMapNode node in nodes) {
				this.AddNode(node, node.ParentNode);
				if (!this.nodes.ContainsKey(node.PageId)) {
					this.nodes.Add(node.PageId, node);
				}
			}
		}

		private mojoSiteMapNode CreateRootNode() {
			string[] rolelist = new string[0];
			mojoSiteMapNode node = new mojoSiteMapNode(this, "-1")
			{
				IsRootNode = true
			};
			this.nodes.Add(-1, node);
			return node;
		}

		private SiteMapNode CreateSiteMapNode(PageSettings page, int depth) {
			string[] rolelist = null;
			string pageUrl;
			if (!string.IsNullOrEmpty(page.AuthorizedRoles)) {
				rolelist = page.AuthorizedRoles.Split(new char[] { ',', ';' }, 0x200);
			}
			if (((page.UseUrl && !page.Url.StartsWith("http")) && (page.Url.Length > 0)) && this.useUrlRewriter) {
				pageUrl = page.Url;
			}
			else {
				pageUrl = "~/Default.aspx?pageid=" + page.PageId.ToString();
			}
			mojoSiteMapNode node = new mojoSiteMapNode(this, page.PageId.ToString(), pageUrl, HttpContext.Current.Server.HtmlEncode(page.PageName), string.Empty, rolelist, null, null, null);
			if ((page.MenuImage.Length > 0) && (page.MenuImage.ToLower().IndexOf("blank") == -1)) {
				node.MenuImage = this.iconBaseUrl + page.MenuImage;
			}
			node.PageGuid = page.PageGuid;
			node.PageId = page.PageId;
			node.ParentId = page.ParentId;
			node.Depth = depth;
			node.ViewRoles = page.AuthorizedRoles;
			node.EditRoles = page.EditRoles;
			node.CreateChildPageRoles = page.CreateChildPageRoles;
			node.CreateChildDraftPageRoles = page.CreateChildDraftRoles;
			node.IncludeInMenu = page.IncludeInMenu;
			node.IncludeInSiteMap = page.IncludeInSiteMap;
			node.IncludeInChildSiteMap = page.IncludeInChildSiteMap;
			node.IncludeInSearchMap = page.IncludeInSearchMap;
			node.LastModifiedUtc = page.LastModifiedUtc;
			node.ChangeFrequency = page.ChangeFrequency;
			node.SiteMapPriority = page.SiteMapPriority;
			node.OpenInNewWindow = page.OpenInNewWindow;
			node.HideAfterLogin = page.HideAfterLogin;
			node.UseSsl = page.RequireSsl && this.sslIsAvailable;
			node.IsPending = page.IsPending;
			node.IsClickable = page.IsClickable;
			node.MenuCssClass = page.MenuCssClass;
			if (!this.nodes.ContainsKey(page.PageId)) {
				this.nodes.Add(page.PageId, node);
			}
			this.CreateChildNodes(node, page, depth + 1);
			this.CreateExpandedChildNodes(node);
			return node;
		}

		private static string GetDepthIndicatorString(int depth) {
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < depth; i++) {
				stringBuilder.Append("-");
			}
			return stringBuilder.ToString();
		}

		private SiteMapNode GetParentNode(PageSettings page) {
			if ((page.ParentId > -1) && this.nodes.ContainsKey(page.ParentId)) {
				return this.nodes[page.ParentId];
			}
			return this.rootNode;
		}

		protected override SiteMapNode GetRootNodeCore() {
			this.BuildSiteMap();
			return this.rootNode;
		}

		public override void Initialize(string name, NameValueCollection config) {
			if (config == null) {
				throw new ArgumentNullException("config");
			}
			if (string.IsNullOrEmpty(name)) {
				name = "mojoSiteMapProvider";
			}
			if (string.IsNullOrEmpty(config["description"])) {
				config.Remove("description");
				config.Add("description", "mojoPortal site map provider");
			}
			this.useUrlRewriter = WebConfigSettings.UseUrlReWriting;
			this.sslIsAvailable = SiteUtils.SslIsAvailable();
			base.Initialize(name, config);
		}

		public void OnSiteMapChanged(string key, object item, CacheItemRemovedReason reason) {
			this.Clear();
		}

		public static void PopulateArrayList(ArrayList arrayList, SiteMapNode siteMapNode) {
			mojoSiteMapNode mojoNode = (mojoSiteMapNode)siteMapNode;
			if (!mojoNode.IsRootNode) {
				mojoNode.DepthIndicator = GetDepthIndicatorString(mojoNode.Depth);
				arrayList.Add(mojoNode);
			}
			foreach (SiteMapNode childNode in mojoNode.ChildNodes) {
				PopulateArrayList(arrayList, childNode);
			}
		}
	}
}

